/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <pthread.h>
#include <securec.h>
#include <malloc.h>

// #include "device_security_level_defines.h"
#include "update_lite_service_proxy.h"

#include "hilog/log.h"
#include "ohos_types.h"


#define MAX_IPC_DATA_LEN 0x100

static int UpdateLiteIpcCallback(IOwner owner, int code, IpcIo *reply)
{
    HILOG_INFO(LOG_CORE, "zxl----UpdateLiteClientProxy------UpdateLiteIpcCallback--------1");
    if (owner == NULL) {
        return ERR_INVALID_PARA;
    }

    uint32_t result, level;
    struct UpdateLiteCallbackHolder *holder = (struct UpdateLiteCallbackHolder *)owner;

    ReadUint32(reply, &result);
    if (result == SUCCESS) {
        ReadUint32(reply, &level);
        HILOG_INFO(LOG_CORE, "[TID:0x%lx] Notify Remote result: %u, level: %u", pthread_self(), result, level);
    } else {
        level = 0;
        HILOG_ERROR(LOG_CORE, "RequestDeviceSecurityLevelSendRequest result value error, ret is %d", result);
    }

    if (holder->callback != NULL) {
        UpdateLiteInfo *info = (UpdateLiteInfo *)malloc(sizeof(UpdateLiteInfo));
        if (info == NULL) {
            return ERR_NO_MEMORY;
        }
        info->magicNum = SECURITY_MAGIC;
        info->result = result;
        info->level = level;
        HILOG_INFO(LOG_CORE, "calling user callback");
        holder->callback(&holder->identity, info);
    }
    // ReadUint32(reply, &level);
    // HILOG_INFO(LOG_CORE, "[TID:0x%lx] Notify Remote result: %u, level: %u", pthread_self(), result, level);
    // ReadUint32(reply, &level);
    // HILOG_INFO(LOG_CORE, "[TID:0x%lx] Notify Remote result: %u, level: %u", pthread_self(), result, level);
    return 0;
}

static BOOL UpdateLiteIpcAsyncCallImpl(IUnknown *iUnknown, const UpdateLiteIdentify identify, const RequestOption option,
    uint32_t cookie, const DeviceSecurityInfoCallback callback)
{
    HILOG_INFO(LOG_CORE, "zxl----UpdateLiteClientProxy------UpdateLiteIpcAsyncCallImpl--------1");
    if (identify.length == 0 || identify.length > DEVICE_ID_MAX_LEN) {
        HILOG_ERROR(LOG_CORE, "RequestDeviceSecurityLevel invalid para len.");
        return ERR_INVALID_PARA;
    }
    struct UpdateLiteCallbackHolder owner = {identify, callback};
    UpdateLiteClientProxy *proxy = (UpdateLiteClientProxy *)iUnknown;
    IpcIo request;
    char data[MAX_IPC_DATA_LEN];
    IpcIoInit(&request, data, MAX_IPC_DATA_LEN, 0);
    /* DeviceIdentify */
    WriteUint32(&request, identify.length);
    WriteBuffer(&request, identify.identity, DEVICE_ID_MAX_LEN);
    /* option */
    WriteUint64(&request, option.challenge);
    WriteUint32(&request, option.timeout);
    WriteUint32(&request, option.extra);
    /* cookie */
    WriteUint32(&request, cookie);
    HILOG_INFO(LOG_CORE, "zxl----UpdateLiteClientProxy------UpdateLiteIpcAsyncCallImpl------cookie = %d", cookie);
    int ret = proxy->Invoke((IClientProxy *)proxy, CMD_SET_DEVICE_SECURITY_LEVEL, &request, &owner, UpdateLiteIpcCallback);
    if (ret != EC_SUCCESS) {
        HILOG_ERROR(LOG_CORE, "RequestDeviceSecurityLevelSendRequest send failed, ret is %d", ret);
        return ret;
    }
    HILOG_INFO(LOG_CORE, "zxl----UpdateLiteClientProxy------UpdateLiteIpcAsyncCallImpl--------return SUCCESS");
    return SUCCESS;
}

void *UpdateLiteCreatClient(const char *service, const char *feature, uint32 size)
{
    HILOG_INFO(LOG_CORE, "UpdateLiteClientProxy------GetClientProxy--------1");
    (void)service;
    (void)feature;
    uint32_t len = size + sizeof(UpdateLiteClientEntry);
    uint8_t *client = (uint8_t *)malloc(len);
    if (client == NULL) {
        HILOG_ERROR(LOG_CORE, "malloc error");
        return NULL;
    }
    (void)memset_s(client, len, 0, len);
    UpdateLiteClientEntry *entry = (UpdateLiteClientEntry *)&client[size];
    entry->ver = ((uint16_t)CLIENT_PROXY_VER | (uint16_t)DEFAULT_VERSION);
    entry->ref = 1;
    entry->iUnknown.QueryInterface = IUNKNOWN_QueryInterface;
    entry->iUnknown.AddRef = IUNKNOWN_AddRef;
    entry->iUnknown.Release = IUNKNOWN_Release;
    entry->iUnknown.Invoke = NULL;
    entry->iUnknown.UpdateLiteIpcAsyncCall = UpdateLiteIpcAsyncCallImpl;
    return client;
}

void UpdateLiteDestroyClient(const char *service, const char *feature, void *proxy)
{
    (void)service;
    (void)feature;
    free(proxy);
}

UpdateLiteClientProxy *GetClientProxy(void)
{
    HILOG_INFO(LOG_CORE, "UpdateLiteClientProxy------GetClientProxy--------1");
    SAMGR_RegisterFactory(UPDATE_LITE_SAMGR_SERVICE, UPDATE_LITE_SAMGR_FEATURE, UpdateLiteCreatClient, UpdateLiteDestroyClient);
    UpdateLiteClientProxy *proxy = NULL;
    HILOG_INFO(LOG_CORE, "[GetFeatureApi S:%s F:%s] begin", UPDATE_LITE_SAMGR_SERVICE, UPDATE_LITE_SAMGR_FEATURE);
    IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(UPDATE_LITE_SAMGR_SERVICE, UPDATE_LITE_SAMGR_FEATURE);
    if (iUnknown == NULL) {
        HILOG_ERROR(LOG_CORE, "[GetFeatureApi S:%s F:%s]: failed", UPDATE_LITE_SAMGR_SERVICE, UPDATE_LITE_SAMGR_FEATURE);
        return NULL;
    }

    int32_t ret = iUnknown->QueryInterface(iUnknown, CLIENT_PROXY_VER, (void **)&proxy);
    if (ret != 0 || proxy == NULL) {
        HILOG_ERROR(LOG_CORE, "[QueryInterface CLIENT_PROXY_VER S:%s, F:%s] failed", UPDATE_LITE_SAMGR_SERVICE,
            UPDATE_LITE_SAMGR_FEATURE);
        return NULL;
    }
    HILOG_INFO(LOG_CORE, "[QueryInterface CLIENT_PROXY_VER S:%s, F:%s] success", UPDATE_LITE_SAMGR_SERVICE, UPDATE_LITE_SAMGR_FEATURE);
    return proxy;
}

void ReleaseClientProxy(UpdateLiteClientProxy *clientProxy)
{
    if (clientProxy == NULL) {
        return;
    }

    int32 ret = clientProxy->Release((IUnknown *)clientProxy);
    HILOG_INFO(LOG_CORE, "[Release api S:%s, F:%s]: ret:%d", UPDATE_LITE_SAMGR_SERVICE, UPDATE_LITE_SAMGR_FEATURE, ret);
}